﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Jewelnoid
{
    class BlockManager
    {
        public Texture2D blockTexture;
        public List<Block> blocksList;
        public List<UnbreakableBlock> unbreakableBlocksList;
        public List<List<int>> blocksMatrix;
        public float blocksStartPosition;
        public int maxColumn;
        public int maxLine;

        private List<List<int>> oldBlocksMatrix;
        private Vector2 windowSize;

        public BlockManager(Texture2D blockTexture, Vector2 windowSize)
        {
            this.blockTexture = blockTexture;
            this.windowSize = windowSize;

            maxColumn = (int)windowSize.X / (blockTexture.Width + 5) - 1;
            maxLine = (int)windowSize.Y / (blockTexture.Height + 5);

            blocksList = new List<Block>();
            unbreakableBlocksList = new List<UnbreakableBlock>();

            blocksStartPosition = 0;

            blocksMatrix = new List<List<int>>();
            oldBlocksMatrix = new List<List<int>>();

            for (int i = 0; i < maxLine; i++)
            {
                List<int> line = new List<int>();
                List<int> oldLine = new List<int>();

                for (int j = 0; j < maxColumn; j++)
                {
                    line.Add(0);
                    oldLine.Add(0);
                }

                blocksMatrix.Add(line);
                oldBlocksMatrix.Add(oldLine);
            }
        }

        public void eraseBlockMatrix()
        {
            for (int i = 0; i < maxLine; i++)
            {
                for (int j = 0; j < maxColumn; j++)
                {
                    blocksMatrix[i][j] = 0;
                }
            }
        }

        public void update()
        {
            if (matrixChange())
            {
                blocksList = new List<Block>();

                for (int i = 0; i < blocksMatrix.Count; i++)
                {
                    for (int j = 0; j < blocksMatrix[i].Count; j++)
                    {
                        if (blocksMatrix[i][j] != 0)
                        {
                            blocksList.Add(new Block(blockTexture, new Vector2(j * (blockTexture.Width + 5) + blocksStartPosition, i * (blockTexture.Height + 5) + 20), Block.numberColorMap[blocksMatrix[i][j]]));
                        }
                    }
                }
            }
        }

        public void draw(SpriteBatch spritebatch)
        {
            if (blocksList != null)
            {
                foreach (Block block in blocksList)
                {
                    block.draw(spritebatch);
                }
            }

            if (unbreakableBlocksList != null)
            {
                foreach (Block block in unbreakableBlocksList)
                {
                    block.draw(spritebatch);
                }
            }
        }

        public int removeBlock(Block blockToRemove)
        {
            int index = blocksList.IndexOf(blockToRemove);
            int count = 0;
            int colorNumber;
            int blocksCount = 0;

            for (int i = 0; i < maxLine; i++)
            {
                for (int j = 0; j < maxColumn; j++)
                {
                    if (blocksMatrix[i][j] != 0)
                    {
                        if (index == count)
                        {
                            colorNumber = blocksMatrix[i][j];

                            blocksMatrix[i][j] = 0;
                            blocksCount++;

                            blocksCount += removeBlocks(i - 1, j, colorNumber);
                            blocksCount += removeBlocks(i + 1, j, colorNumber);
                            blocksCount += removeBlocks(i, j - 1, colorNumber);
                            blocksCount += removeBlocks(i, j + 1, colorNumber);

                            return blocksCount;
                        }
                        count++;
                    }
                }
            }

            return blocksCount;
        }

        public Boolean isBlockMatrixEmpty()
        {
            for (int i = 0; i < maxLine; i++)
            {
                for (int j = 0; j < maxColumn; j++)
                {
                    if (blocksMatrix[i][j] != 0)
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        private int removeBlocks(int iStart, int jStart, int colorNumber)
        {
            int blocksCount = 0;

            try
            {
                if (blocksMatrix[iStart][jStart] == colorNumber)
                {
                    blocksMatrix[iStart][jStart] = 0;
                    blocksCount++;

                    blocksCount += removeBlocks(iStart - 1, jStart, colorNumber);
                    blocksCount += removeBlocks(iStart + 1, jStart, colorNumber);
                    blocksCount += removeBlocks(iStart, jStart - 1, colorNumber);
                    blocksCount += removeBlocks(iStart, jStart + 1, colorNumber);
                }

                return blocksCount;
            }
            catch (ArgumentOutOfRangeException e)
            {
                //"Calma, ta tudo bem agora" - Entei
                //É esperado que ocorre uma exceção aqui, pois pode ser que o iStart e o jStart se refirão a posições inexistentes.
                //Se for o caso simplismente nada é feito
                return blocksCount;
            }
        }

        //Apenas para teste
        public void printMatrix()
        {
            String line;

            Console.Write("\n\nMatrix:\n");

            for (int i = 0; i < blocksMatrix.Count; i++)
            {
                line = "| ";

                for (int j = 0; j < blocksMatrix[i].Count; j++)
                {
                    line = String.Concat(line, blocksMatrix[i][j]);
                }

                line = String.Concat(line, " |\n");
                Console.Write(line);
            }
        }

        private Boolean matrixChange()
        {
            if (oldBlocksMatrix.Count == blocksMatrix.Count)
            {
                for (int i = 0; i < blocksMatrix.Count; i++)
                {
                    if (blocksMatrix[i].Count != oldBlocksMatrix[i].Count)
                    {
                        updateOldMatrix();
                        return true;
                    }

                    for (int j = 0; j < blocksMatrix[i].Count; j++)
                    {
                        if (blocksMatrix[i][j] != oldBlocksMatrix[i][j])
                        {
                            updateOldMatrix();
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        private void updateOldMatrix()
        {
            for (int i = 0; i < blocksMatrix.Count; i++)
            {
                for (int j = 0; j < blocksMatrix[i].Count; j++)
                {
                    oldBlocksMatrix[i][j] = blocksMatrix[i][j];
                }
            }
        }

        private int getMaxColumnWithBlocks()
        {
            int columnNumber = 0;

            for (int i = 0; i < blocksMatrix.Count; i++)
            {
                for (int j = 0; j < blocksMatrix[i].Count; j++)
                {
                    if (blocksMatrix[i][j] != 0 && j > columnNumber)
                    {
                        columnNumber = j;
                    }
                }
            }

            return columnNumber;
        }
    }
}
